package com.kc.gb.device.plugins.strip.service.impl;

import com.kc.gb.device.common.utils.SpringHelper;
import com.kc.gb.device.plugins.strip.StripHardware;
import com.kc.gb.device.plugins.strip.dto.StripLightState;
import com.kc.gb.device.plugins.strip.listener.support.StripCommandEvent;
import com.kc.gb.device.plugins.strip.service.StripHardwareService;
import com.kc.gb.feign.strip.sopport.dto.StripCommand;
import com.kc.gb.feign.strip.sopport.enums.StripLightOnOff;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class StripHardwareServiceImpl implements StripHardwareService {

    @Resource
    StripHardware stripHardware;

    private Map<Integer,StripLightState> SIMULATE_STATE_STORE = new ConcurrentHashMap<>();
    private Map<Integer,StripLightState> DEBUGGER_STATE_STORE = new ConcurrentHashMap<>();

    @Value("${light.strip.device.addr:1}")
    private Integer addr;

    @Value("${light.strip.color:28}")
    private int color;

    @Override
    public void consumeCommands(List<StripCommand> commands, boolean isDebugMode) {
        if(CollectionUtils.isEmpty(commands)){
            return;
        }
        Exception lastException = null;
        for (StripCommand command : commands) {
            try {
                // PTL command event 通知前端界面刷新
                SpringHelper.getApplicationContext().publishEvent(new StripCommandEvent(command));
                StripLightOnOff lightOnOff = command.getLightOnOff();
                if(StripLightOnOff.LIGHT_ON.equals(lightOnOff)){
                    openLight(isDebugMode,command.getLightNo());
                }else if(StripLightOnOff.LIGHT_OFF.equals(lightOnOff)){
                    closeLight(isDebugMode,command.getLightNo());
                }
            } catch (Exception e) {
                // 硬件连接异常时，保证模拟器所有指令执行完毕
                log.error(e.getMessage(),e);
                lastException = e;
            }
        }
        // 抛出异常信息
        if(ObjectUtils.isNotEmpty(lastException)){
            throw new RuntimeException(lastException);
        }
    }

    /**
     * 打开灯珠
     */
    @Override
    public void openLight(boolean isDebugMode, List<Integer> positions) {
        CollectionUtils.emptyIfNull(positions).forEach(position -> {
            // 多个灯的控制需要捕获每个灯珠的异常，防止对其他灯珠的影响
            try {
                getLightState(isDebugMode,position).turnOn();
                stripHardware.getAtopControl().AB_LED_Strip_DSP(addr.byteValue(), position.byteValue(), position.byteValue(), (byte) color,(byte) 0);
            } catch (Exception e) {
                log.error("LightStrip openLight | position:{} error:{}", position,e.getMessage(),e);
            }
        });
    }

    /**
     * 关闭灯珠
     */
    @Override
    public void closeLight(boolean isDebugMode, List<Integer> positions) {
        CollectionUtils.emptyIfNull(positions).forEach(position -> {
            // 多个灯的控制需要捕获每个灯珠的异常，防止对其他灯珠的影响
            try {
                getLightState(isDebugMode,position).turnOff();
                stripHardware.getAtopControl().AB_LED_Strip_DSP(addr.byteValue(), position.byteValue(), position.byteValue(), (byte) 12, (byte) 0);
            } catch (Exception e) {
                log.error("LightStrip closeLight | position:{} error:{}", position,e.getMessage(),e);
            }
        });
    }

    @Override
    public Map<Integer, StripLightState> getStateStore(boolean inDebugMode) {
        if(inDebugMode){
            return DEBUGGER_STATE_STORE;
        }
        return SIMULATE_STATE_STORE;
    }

    @Override
    public StripLightState getLightState(boolean inDebugMode, Integer lightNos) {
        List<StripLightState> states = getLightStates(inDebugMode, Collections.singletonList(lightNos));
        return states.get(0);
    }

    @Override
    public List<StripLightState> getLightStates(boolean inDebugMode, List<Integer> lightNos) {
        Map<Integer,StripLightState> stateStore = getStateStore(inDebugMode);
        if(inDebugMode){
            stateStore = DEBUGGER_STATE_STORE;
        }else{
            stateStore = SIMULATE_STATE_STORE;
        }
        if(CollectionUtils.isEmpty(lightNos)){
            return new ArrayList<>();
        }
        List<StripLightState> states = new ArrayList<>();
        for (Integer lightNo : lightNos) {
            StripLightState exist = stateStore.get(lightNo);
            if(ObjectUtils.isEmpty(exist)){
                StripLightState defaultState = new StripLightState(lightNo);
                stateStore.put(lightNo,defaultState);
            }
            states.add(stateStore.get(lightNo));
        }
        return states;
    }
}
